/*
 * Created on 2005-3-12
 *
 */
package bma.common.langutil.bean.impl;

import java.lang.reflect.Array;
import java.lang.reflect.Method;

import bma.common.langutil.bean.AccessType;
import bma.common.langutil.bean.BeanType;
import bma.common.langutil.core.ArrayUtil;
import bma.common.langutil.core.DirectInvoker;
import bma.common.langutil.core.ExceptionUtil;

/**
 * 
 * @author guanzhong
 * @since 1.0 (imported from BMA.ESP Project)
 * 
 */
public class NativeArrayProperty extends BeanObjectPropertyAbstract {

	private Method getMethod;

	private Method setMethod;

	public NativeArrayProperty() {
		super();
	}

	public BeanType getPropertyType() {
		return BeanType.LIST;
	}

	@Override
	public boolean accessible(AccessType type) {

		if (!super.accessible(type))
			return false;

		switch (type) {
		case INDEX_GET:
		case SIZE:
			return getMethod != null;
		case INDEX_SET:
		case ADD:
		case INDEX_REMOVE:
			return setMethod != null && getMethod != null;
		default:
			return false;
		}
	}

	@Override
	public Object get(Object thisObject) {
		throw new RuntimeException("Not implemented");
	}

	public Object get(Object thisObject, int index) {
		if (thisObject == null) {
			throw new NullPointerException("this object");
		}
		if (getMethod == null) {
			throw new NullPointerException("getMethod[" + getName() + "]");
		}

		try {
			Object[] v = (Object[]) DirectInvoker.invoke(thisObject, getMethod,
					null);
			if (v == null || index < 0 || index >= v.length) {
				throw new IndexOutOfBoundsException("Index: " + index
						+ ", Size: " + (v == null ? 0 : v.length));
			}
			return v[index];

		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}

	}

	public Object get(Object thisObject, String key) {
		throw new RuntimeException("Not implemented");
	}

	public int size(Object thisObject) {
		if (thisObject == null) {
			throw new NullPointerException("this object");
		}
		if (getMethod == null) {
			throw new NullPointerException("getMethod[" + getName() + "]");
		}

		try {
			Object[] v = (Object[]) DirectInvoker.invoke(thisObject, getMethod,
					null);
			return v == null ? 0 : v.length;

		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}
	}

	public void remove(Object thisObject, int index) {
		if (thisObject == null) {
			throw new NullPointerException("this object");
		}
		if (getMethod == null) {
			throw new NullPointerException("getMethod[" + getName() + "]");
		}
		if (setMethod == null) {
			throw new NullPointerException("setMethod[" + getName() + "]");
		}

		try {
			Object v = DirectInvoker.invoke(thisObject, getMethod, null);
			if (v == null || index < 0 || index >= Array.getLength(v)) {
				throw new IndexOutOfBoundsException("Index: " + index
						+ ", Size: " + (v == null ? 0 : Array.getLength(v)));
			}
			v = ArrayUtil.remove(v, index);

			DirectInvoker.invoke(thisObject, setMethod, new Object[] { v });

		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}
	}

	public void remove(Object thisObject, String key) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void set(Object thisObject, Object value) {
		throw new RuntimeException("Not implemented");
	}

	public void add(Object thisObject, Object value) {
		if (thisObject == null) {
			throw new NullPointerException("this object");
		}
		if (getMethod == null) {
			throw new NullPointerException("getMethod[" + getName() + "]");
		}
		if (setMethod == null) {
			throw new NullPointerException("setMethod[" + getName() + "]");
		}

		try {
			Object v = DirectInvoker.invoke(thisObject, getMethod, null);
			if (v == null) {
				Class cls = getMethod.getReturnType();
				v = (Object) Array.newInstance(cls.getComponentType(), 0);
			}
			v = ArrayUtil.add(v, value);

			DirectInvoker.invoke(thisObject, setMethod, new Object[] { v });

		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}
	}

	public void set(Object thisObject, int index, Object value) {
		if (thisObject == null) {
			throw new NullPointerException("this object");
		}
		if (getMethod == null) {
			throw new NullPointerException("getMethod[" + getName() + "]");
		}
		if (setMethod == null) {
			throw new NullPointerException("setMethod[" + getName() + "]");
		}

		try {
			Object[] v = (Object[]) DirectInvoker.invoke(thisObject, getMethod,
					null);
			if (v == null || index < 0 || index >= v.length) {
				throw new IndexOutOfBoundsException("Index: " + index
						+ ", Size: " + (v == null ? 0 : v.length));
			}
			v[index] = value;

			DirectInvoker.invoke(thisObject, setMethod, new Object[] { v });

		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}
	}

	public void set(Object thisObject, String key, Object value) {
		throw new RuntimeException("Not implemented");
	}

	public String[] keys(Object thisObject) {
		throw new RuntimeException("Not implemented");
	}

	/**
	 * @return Returns the getMethod.
	 */
	public Method getGetMethod() {
		return getMethod;
	}

	/**
	 * @param getMethod
	 *            The getMethod to set.
	 */
	public void setGetMethod(Method getMethod) {
		this.getMethod = getMethod;
	}

	/**
	 * @return Returns the setMethod.
	 */
	public Method getSetMethod() {
		return setMethod;
	}

	/**
	 * @param setMethod
	 *            The setMethod to set.
	 */
	public void setSetMethod(Method setMethod) {
		this.setMethod = setMethod;
	}

}
